/* Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.jenkins.flakyTestHandler.plugin; /** * * Test aggregation logic * * @author Qingzhou Luo */ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import com.google.jenkins.flakyTestHandler.plugin.FlakyTestResultAction.FlakyRunStats; import com.google.jenkins.flakyTestHandler.plugin.HistoryAggregatedFlakyTestResultAction.SingleTestFlakyStats; import com.google.jenkins.flakyTestHandler.plugin.HistoryAggregatedFlakyTestResultAction.SingleTestFlakyStatsWithRevision; import com.google.jenkins.flakyTestHandler.plugin.deflake.DeflakeCause; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import hudson.model.AbstractBuild; import hudson.model.CauseAction; import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; public class HistoryAggregatedFlakyTestResultActionTest { private final static String TEST_ONE = "testOne"; private final static String TEST_TWO = "testTwo"; private final static String TEST_THREE = "testThree"; private final static String TEST_FOUR = "testFour"; private final static String REVISION_ONE = "revision_one"; private final static String REVISION_TWO = "revision_two"; private final static int TOTAL_RUNS = 2; @Rule public JenkinsRule jenkins = new JenkinsRule(); @Test public void testAggregateFlakyRunsWithRevisions() throws Exception { FreeStyleProject project = jenkins.createFreeStyleProject("project"); List<AbstractBuild> buildList = new ArrayList<AbstractBuild>(); for (FlakyTestResultAction action : setUpFlakyTestResultAction()) { FreeStyleBuild build = new FreeStyleBuild(project); build.addAction(action); buildList.add(build); } HistoryAggregatedFlakyTestResultAction action = new HistoryAggregatedFlakyTestResultAction( null); for (AbstractBuild build : buildList) { action.aggregateOneBuild(build); } Map<String, Map<String, SingleTestFlakyStats>> statsMapOverRevision = action.getAggregatedTestFlakyStatsWithRevision(); // TEST_ONE SingleTestFlakyStats testOneRevisionOneStats = statsMapOverRevision.get(TEST_ONE) .get(REVISION_ONE); assertEquals("wrong number passes", 2, testOneRevisionOneStats.getPass()); assertEquals("wrong number fails", 0, testOneRevisionOneStats.getFail()); assertEquals("wrong number flakes", 0, testOneRevisionOneStats.getFlake()); SingleTestFlakyStats testOneRevisionTwoStats = statsMapOverRevision.get(TEST_ONE) .get(REVISION_TWO); assertEquals("wrong number passes", 1, testOneRevisionTwoStats.getPass()); assertEquals("wrong number fails", 1, testOneRevisionTwoStats.getFail()); assertEquals("wrong number flakes", 0, testOneRevisionTwoStats.getFlake()); // TEST_TWO SingleTestFlakyStats testTwoRevisionOneStats = statsMapOverRevision.get(TEST_TWO) .get(REVISION_ONE); assertEquals("wrong number passes", 1, testTwoRevisionOneStats.getPass()); assertEquals("wrong number fails", 3, testTwoRevisionOneStats.getFail()); assertEquals("wrong number flakes", 0, testTwoRevisionOneStats.getFlake()); SingleTestFlakyStats testTwoRevisionTwoStats = statsMapOverRevision.get(TEST_TWO) .get(REVISION_TWO); assertEquals("wrong number passes", 1, testTwoRevisionTwoStats.getPass()); assertEquals("wrong number fails", 0, testTwoRevisionTwoStats.getFail()); assertEquals("wrong number flakes", 0, testTwoRevisionTwoStats.getFlake()); // TEST_THREE SingleTestFlakyStats testThreeRevisionOneStats = statsMapOverRevision.get(TEST_THREE) .get(REVISION_ONE); assertEquals("wrong number passes", 1, testThreeRevisionOneStats.getPass()); assertEquals("wrong number fails", 2, testThreeRevisionOneStats.getFail()); assertEquals("wrong number flakes", 0, testThreeRevisionOneStats.getFlake()); SingleTestFlakyStats testThreeRevisionTwoStats = statsMapOverRevision.get(TEST_THREE) .get(REVISION_TWO); assertEquals("wrong number passes", 0, testThreeRevisionTwoStats.getPass()); assertEquals("wrong number fails", 2, testThreeRevisionTwoStats.getFail()); assertEquals("wrong number flakes", 0, testThreeRevisionTwoStats.getFlake()); // TEST_FOUR SingleTestFlakyStats testFourRevisionOneStats = statsMapOverRevision.get(TEST_FOUR) .get(REVISION_ONE); assertEquals("wrong number passes", 1, testFourRevisionOneStats.getPass()); assertEquals("wrong number fails", 3, testFourRevisionOneStats.getFail()); assertEquals("wrong number flakes", 0, testFourRevisionOneStats.getFlake()); SingleTestFlakyStats testFourRevisionTwoStats = statsMapOverRevision.get(TEST_FOUR) .get(REVISION_TWO); assertEquals("wrong number passes", 1, testFourRevisionTwoStats.getPass()); assertEquals("wrong number fails", 0, testFourRevisionTwoStats.getFail()); assertEquals("wrong number flakes", 0, testFourRevisionTwoStats.getFlake()); } @Test public void testAggregate() throws Exception { FreeStyleProject project = jenkins.createFreeStyleProject("project"); List<FlakyTestResultAction> flakyTestResultActions = setUpFlakyTestResultAction(); List<FlakyTestResultAction> flakyTestResultActionList = new ArrayList<FlakyTestResultAction>( flakyTestResultActions); // First non-deflake build AbstractBuild firstBuild = (AbstractBuild) project .scheduleBuild2(0, flakyTestResultActionList.get(0)).get(); while (firstBuild.isBuilding()) { Thread.sleep(100); } // Second deflake build AbstractBuild secondBuild = (AbstractBuild) project .scheduleBuild2(0, flakyTestResultActionList.get(1), new CauseAction(new DeflakeCause(firstBuild))).get(); while (secondBuild.isBuilding()) { Thread.sleep(100); } // Third deflake build with HistoryAggregatedFlakyTestResultAction AbstractBuild thirdBuild = (AbstractBuild) project .scheduleBuild2(0, flakyTestResultActionList.get(2), new HistoryAggregatedFlakyTestResultAction(project)).get(); while (thirdBuild.isBuilding()) { Thread.sleep(100); } HistoryAggregatedFlakyTestResultAction action = thirdBuild .getAction(HistoryAggregatedFlakyTestResultAction.class); action.aggregate(); Map<String, SingleTestFlakyStats> aggregatedFlakyStatsMap = action.getAggregatedFlakyStats(); // Make sure revisions are inserted in the order of their appearance Map<String, SingleTestFlakyStats> revisionMap = action.getAggregatedTestFlakyStatsWithRevision() .get(TEST_ONE); assertArrayEquals("Incorrect revision history", new String[]{REVISION_ONE, REVISION_TWO}, revisionMap.keySet().toArray(new String[revisionMap.size()])); assertEquals("wrong number of entries for flaky stats", 4, aggregatedFlakyStatsMap.size()); SingleTestFlakyStats testOneStats = aggregatedFlakyStatsMap.get(TEST_ONE); SingleTestFlakyStats testTwoStats = aggregatedFlakyStatsMap.get(TEST_TWO); SingleTestFlakyStats testThreeStats = aggregatedFlakyStatsMap.get(TEST_THREE); SingleTestFlakyStats testFourStats = aggregatedFlakyStatsMap.get(TEST_FOUR); assertEquals("wrong number passes", 1, testOneStats.getPass()); assertEquals("wrong number fails", 0, testOneStats.getFail()); assertEquals("wrong number flakes", 1, testOneStats.getFlake()); assertEquals("wrong number passes", 1, testTwoStats.getPass()); assertEquals("wrong number fails", 0, testTwoStats.getFail()); assertEquals("wrong number flakes", 1, testTwoStats.getFlake()); assertEquals("wrong number passes", 0, testThreeStats.getPass()); assertEquals("wrong number fails", 1, testThreeStats.getFail()); assertEquals("wrong number flakes", 1, testThreeStats.getFlake()); assertEquals("wrong number passes", 1, testFourStats.getPass()); assertEquals("wrong number fails", 0, testFourStats.getFail()); assertEquals("wrong number flakes", 1, testFourStats.getFlake()); } public static List<FlakyTestResultAction> setUpFlakyTestResultAction() { FlakyTestResultAction actionOne = new FlakyTestResultAction(); FlakyTestResultAction actionTwo = new FlakyTestResultAction(); FlakyTestResultAction actionThree = new FlakyTestResultAction(); Map<String, SingleTestFlakyStatsWithRevision> testFlakyStatsWithRevisionMap = new HashMap<String, SingleTestFlakyStatsWithRevision>(); testFlakyStatsWithRevisionMap.put(TEST_ONE, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.PASSED)); testFlakyStatsWithRevisionMap.put(TEST_TWO, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.FAILED)); testFlakyStatsWithRevisionMap.put(TEST_THREE, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.PASSED)); testFlakyStatsWithRevisionMap.put(TEST_FOUR, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.FLAKED)); FlakyRunStats actionOneResult = new FlakyRunStats(testFlakyStatsWithRevisionMap); testFlakyStatsWithRevisionMap = new HashMap<String, SingleTestFlakyStatsWithRevision>(); testFlakyStatsWithRevisionMap.put(TEST_ONE, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.PASSED)); testFlakyStatsWithRevisionMap.put(TEST_TWO, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.FLAKED)); testFlakyStatsWithRevisionMap.put(TEST_THREE, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.FAILED)); testFlakyStatsWithRevisionMap.put(TEST_FOUR, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_ONE, TestState.FAILED)); FlakyRunStats actionTwoResult = new FlakyRunStats(testFlakyStatsWithRevisionMap); testFlakyStatsWithRevisionMap = new HashMap<String, SingleTestFlakyStatsWithRevision>(); testFlakyStatsWithRevisionMap.put(TEST_ONE, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_TWO, TestState.FLAKED)); testFlakyStatsWithRevisionMap.put(TEST_TWO, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_TWO, TestState.PASSED)); testFlakyStatsWithRevisionMap.put(TEST_THREE, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_TWO, TestState.FAILED)); testFlakyStatsWithRevisionMap.put(TEST_FOUR, createSingleTestFlakyStatsWithRevision(TOTAL_RUNS, REVISION_TWO, TestState.PASSED)); FlakyRunStats actionThreeResult = new FlakyRunStats(testFlakyStatsWithRevisionMap); actionOne.setFlakyRunStats(actionOneResult); actionTwo.setFlakyRunStats(actionTwoResult); actionThree.setFlakyRunStats(actionThreeResult); List<FlakyTestResultAction> actionList = new ArrayList<FlakyTestResultAction>(); actionList.add(actionOne); actionList.add(actionTwo); actionList.add(actionThree); return actionList; } private static enum TestState { PASSED, FAILED, FLAKED; } /** * Create a {@link SingleTestFlakyStatsWithRevision} object for testing * * @param totalRuns number of maximal number of potential runs in this bulid. Assume if a test is * flaky, it will fail in all previous totalRuns-1 retries but pass in the last time. * @param revision the revision this build was run * @param result result of a single test * @return a {@link SingleTestFlakyStatsWithRevision} object which contains the revision * information and the number of passes/fails for the test */ private static SingleTestFlakyStatsWithRevision createSingleTestFlakyStatsWithRevision( int totalRuns, String revision, TestState result) { SingleTestFlakyStats stats; if (result == TestState.PASSED) { stats = new SingleTestFlakyStats(1, 0, 0); } else if (result == TestState.FAILED) { stats = new SingleTestFlakyStats(0, totalRuns, 0); } else { stats = new SingleTestFlakyStats(1, totalRuns - 1, 0); } return new SingleTestFlakyStatsWithRevision(stats, revision); } }